#ifndef ENGINE_H_
#define ENGINE_H_


#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <map>
#include <list>
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <io.h>
#include <algorithm>
#include <boost/timer.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include "noise/noise.h"
#include "noiseutils.h"
#include <omp.h>

//DirectX headers
#define DIRECTINPUT_VERSION 0x0800
#include <d3d9.h>
#include <d3dx9.h>
#include <dinput.h>

//engine includes
#include "Timer.h"
#include "Input.h"
#include "Event.h"
#include "Font.h"
#include "LogFile.h"
#include "Math.h"
#include "Vector.h"
#include "Matrix.h"
#include "Camera.h"


//required libs
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"dinput8.lib")
#pragma comment(lib,"xinput.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")


#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define REVISION 0

//end user functions
extern bool Game_Preload();
extern bool Game_Init(HWND hWnd);
extern void Game_Update(double deltaTime);
extern void Game_Render3d();
extern void Game_Render2d();
extern void Game_Event(TSS::IEvent* e);
extern void Game_End();

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

namespace TSS
{
	//helper convert values to string format
	template <class T>std::string static ToString(const T &t, int places = 2)
	{
		std::ostringstream oss;
		oss.precision(places);
		oss.setf(std::ios_base::fixed);
		oss << t;
		return oss.str();
	}

	class Engine
	{
		std::string p_commandLineParams;
		int p_versionMajor, p_versionMinor, p_revision;
		HWND p_hWnd;
		LPDIRECT3D9 p_d3d;
		LPDIRECT3DDEVICE9 p_device;
		LPD3DXSPRITE p_sprite;
		std::string p_appTitle;
		bool p_fullscreen;
		int p_screenWidth;
		int p_screenHeight;
		int p_colorDepth;
		bool p_pauseMode;
		Timer p_coreTimer;
		long p_coreFrameCount;
		long p_coreFrameRate;
		Timer p_screenTimer;
		long p_screenFrameCount;
		long p_screenFrameRate;
		Timer timedUpdate;
		D3DCOLOR p_backdropColor;

		//primary surface pointers used when restoring render target
		LPDIRECT3DSURFACE9 p_MainSurface;
		LPDIRECT3DSURFACE9 p_MainDepthStencilSurface;

		Input *p_input;
		void updateKeyboard();
		void updateMouse();

	public:

		Engine();
		virtual ~Engine();
		bool Init(HINSTANCE hInstance, int width, int height, int colorDepth, bool fullscreen);
		void Update(double deltaTime);
		void Message(std::string message, std::string title = "Engine");
		void fatalError(std::string message, std::string title = "FATAL ERROR");
		void Shutdown();
		void ClearScene(D3DCOLOR color);
		void SetIdentity();
		void SetSpriteIdentity();
		int Release();
		void SavePrimaryRenderTarget();
		void RestorePrimaryRenderTarget();

		//accessor/mutator
		bool isPaused() {return p_pauseMode; }
		void setPaused(bool b) { p_pauseMode = b; }
		LPDIRECT3DDEVICE9 getDevice() { return p_device; }
		LPD3DXSPRITE getSpriteObj() { return p_sprite; }

		void setWindowHandle(HWND hwnd) { p_hWnd = hwnd; }
		HWND getWindowHandle() { return p_hWnd; }

		std::string getAppTitle() { return p_appTitle; }
		void setAppTitle(std::string value) { p_appTitle = value; }

		int getVersionMajor() { return p_versionMajor; }
		int getVersionMinor() { return p_versionMinor; }
		int getRevision() { return p_revision; }
		std::string getVersionText();

		long getCoreFrameRate() { return p_coreFrameRate; };
		long getScreenFrameRate() { return p_screenFrameRate; };

		void setScreen(int w,int h,int d,bool full);
		int getScreenWidth() { return p_screenWidth; }
		void setScreenWidth(int value) { p_screenWidth = value; }
		int getScreenHeight() { return p_screenHeight; }
		void setScreenHeight(int value) { p_screenHeight = value; }
		int getColorDepth() { return p_colorDepth; }
		void setColorDepth(int value) { p_colorDepth = value; }
		bool getFullscreen() { return p_fullscreen; }
		void setFullscreen(bool value) { p_fullscreen = value; }

		D3DCOLOR getBackdropColor() { return p_backdropColor; }
		void setBackdropColor(D3DCOLOR value) { p_backdropColor = value; }

		//command line params
		std::string getCommandLineParams() { return p_commandLineParams; }
		void setCommandLineParams(std::string s) { p_commandLineParams = s; }

		//event system
		void raiseEvent(IEvent*);

	};

};

//define the global engine object (visible everywhere!)
extern std::auto_ptr<TSS::Engine> g_engine;

#endif